﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Badge_Manager.Model;

namespace Badge_Manager.Controller
{
    public class ctrlAttivitaDettaglio
    {
        private Connector gazelConnector = Connector.Istance();
        private Attivita attivita;
        private List<DettaglioAttivita> listaDettagli;
        private double durataStandardMinuti = 0;

        public List<DettaglioAttivita> DettagliAttivita { get { return listaDettagli; } set { listaDettagli = value; } }

        public ctrlAttivitaDettaglio(Attivita attivita)
        {
            this.attivita = attivita;
            if (attivita != null && attivita.DettagliAttivita != null)
                listaDettagli = attivita.DettagliAttivita;
            else
                listaDettagli = new List<DettaglioAttivita>();
        }

        /// <summary>
        /// Inserisce in tabella DettAttivita
        /// </summary>
        /// <param name="attivita">Restituisce il numero di righe modificate;-1 se va in err</param>
        public int Inserisci()
        {
            try
            {
                string query;
                int righeinserite = 0;

                foreach (DettaglioAttivita dettaglio in attivita.DettagliAttivita)
                {
                    query = "INSERT INTO DettaglioAttivita "
                        + "VALUES(@id,@idattivita,@giorno,@orainizio,@orafine,@minutiinizio,@minutifine)";

                    SqlCommand insert = new SqlCommand(query, gazelConnector.Connessione);

                    SqlParameter id = new SqlParameter();
                    id.ParameterName = "@id";
                    id.SqlDbType = SqlDbType.UniqueIdentifier;
                    id.Value = dettaglio.Id;
                    insert.Parameters.Add(id);

                    SqlParameter idattivita = new SqlParameter();
                    idattivita.ParameterName = "@idattivita";
                    idattivita.SqlDbType = SqlDbType.UniqueIdentifier;
                    idattivita.Value = attivita.Id;
                    insert.Parameters.Add(idattivita);

                    SqlParameter giorno = new SqlParameter();
                    giorno.ParameterName = "@giorno";
                    giorno.SqlDbType = SqlDbType.Date;
                    giorno.Value = dettaglio.Giorno;
                    insert.Parameters.Add(giorno);

                    SqlParameter orainizio = new SqlParameter();
                    orainizio.ParameterName = "@orainizio";
                    orainizio.SqlDbType = SqlDbType.Int;
                    orainizio.Value = dettaglio.OraInizio;
                    insert.Parameters.Add(orainizio);

                    SqlParameter orafine = new SqlParameter();
                    orafine.ParameterName = "@orafine";
                    orafine.SqlDbType = SqlDbType.Int;
                    orafine.Value = dettaglio.OraFine;
                    insert.Parameters.Add(orafine);

                    SqlParameter minutiinizio = new SqlParameter();
                    minutiinizio.ParameterName = "@minutiinizio";
                    minutiinizio.SqlDbType = SqlDbType.Int;
                    minutiinizio.Value = dettaglio.MinutiInizio;
                    insert.Parameters.Add(minutiinizio);

                    SqlParameter minutifine = new SqlParameter();
                    minutifine.ParameterName = "@minutifine";
                    minutifine.SqlDbType = SqlDbType.Int;
                    minutifine.Value = dettaglio.MinutiFine;
                    insert.Parameters.Add(minutifine);

                    righeinserite += insert.ExecuteNonQuery();
                }
                return righeinserite;
            }
            catch
            {
                return -1;
            }
        }

        public int Modifica()
        {
            try
            {
                string query;
                int righeinserite = 0;

                query = "UPDATE DettaglioAttivita SET"
                    + " giorno=@giorno,orainizio=@orainizio,orafine=@orafine,minutiinizio=@minutiinizio"
                    + ",minutifine=@minutifine "
                    + " where idattivita=@condizione and id=@condizione2";

                foreach (DettaglioAttivita dettaglio in attivita.DettagliAttivita)
                {
                    SqlCommand update = new SqlCommand(query, gazelConnector.Connessione);
                    SqlParameter giorno = new SqlParameter();
                    giorno.ParameterName = "@giorno";
                    giorno.SqlDbType = SqlDbType.Date;
                    giorno.Value = dettaglio.Giorno;
                    update.Parameters.Add(giorno);

                    SqlParameter orainizio = new SqlParameter();
                    orainizio.ParameterName = "@orainizio";
                    orainizio.SqlDbType = SqlDbType.Int;
                    orainizio.Value = dettaglio.OraInizio;
                    update.Parameters.Add(orainizio);

                    SqlParameter orafine = new SqlParameter();
                    orafine.ParameterName = "@orafine";
                    orafine.SqlDbType = SqlDbType.Int;
                    orafine.Value = dettaglio.OraFine;
                    update.Parameters.Add(orafine);

                    SqlParameter minutiinizio = new SqlParameter();
                    minutiinizio.ParameterName = "@minutiinizio";
                    minutiinizio.SqlDbType = SqlDbType.Int;
                    minutiinizio.Value = dettaglio.MinutiInizio;
                    update.Parameters.Add(minutiinizio);

                    SqlParameter minutifine = new SqlParameter();
                    minutifine.ParameterName = "@minutifine";
                    minutifine.SqlDbType = SqlDbType.Int;
                    minutifine.Value = dettaglio.MinutiFine;
                    update.Parameters.Add(minutifine);

                    SqlParameter idattivita = new SqlParameter();
                    idattivita.ParameterName = "@condizione";
                    idattivita.SqlDbType = SqlDbType.UniqueIdentifier;
                    idattivita.Value = attivita.Id;
                    update.Parameters.Add(idattivita);

                    SqlParameter id = new SqlParameter();
                    id.ParameterName = "@condizione2";
                    id.SqlDbType = SqlDbType.UniqueIdentifier;
                    id.Value = dettaglio.Id;
                    update.Parameters.Add(id);

                    righeinserite += update.ExecuteNonQuery();
                }
                return righeinserite;
            }
            catch
            {
                return -1;
            }
        }

        /// <summary>
        /// Rimuove un singolo record dalla tabella DettaglioAttivita
        /// </summary>
        /// <param name="Id"></param>
        /// <returns>Il numero di righe rimosse</returns>
        public int CancellaRiga(Guid Id)
        {
            string query;
            query = "DELETE FROM DettaglioAttivita "
                + " WHERE id='" + Id + "'";

            SqlCommand insert = new SqlCommand(query, gazelConnector.Connessione);
            return insert.ExecuteNonQuery();
        }

        public int CancellaDettagli(Guid IdAttivita)
        {
            string query;
            query = "DELETE FROM DettaglioAttivita "
                + " WHERE idattivita='" + IdAttivita + "'";

            SqlCommand insert = new SqlCommand(query, gazelConnector.Connessione);
            return insert.ExecuteNonQuery();
        }

        public DataTable GetDettagliCorsoById(Guid id)
        {
            string query;
            query = "SELECT DettaglioAttivita.id, Corsi.nome AS NomeCorso, Attivita.descrizione AS Attivita, Stanze.numero AS StanzaNumero, DettaglioAttivita.giorno AS Giorno, DettaglioAttivita.orainizio AS OraInizio, "
                + "DettaglioAttivita.orafine AS OraFine,DettaglioAttivita.minutiinizio AS MinutiInizio,DettaglioAttivita.minutifine AS MinutiFine "
                + "FROM Corsi INNER JOIN "
                + "Attivita ON Corsi.id = Attivita.idcorso INNER JOIN "
                + "Stanze ON Attivita.idstanza = Stanze.id INNER JOIN "
                + "DettaglioAttivita ON Attivita.id = DettaglioAttivita.idattivita and Attivita.id = '" + id + "'"
                + " ORDER BY Giorno";
            SqlDataAdapter com = new SqlDataAdapter(query, gazelConnector.Connessione);
            DataTable dt = new DataTable();
            com.Fill(dt);
            return dt;
        }

        public List<DettaglioAttivita> GeneraElencoAttivitaDett(DateTime oraDa, DateTime oraA,
            bool calcolapausapranzo)
        {
            if (listaDettagli.Count > 0)
                listaDettagli.Clear();

            int bufferNumeroOre = attivita.Corso.NumeroOre;
            return InserisciOreRimanenti(attivita.Corso.DataInizio, oraDa, oraA, calcolapausapranzo, bufferNumeroOre);
        }

        private List<DettaglioAttivita> InserisciOreRimanenti(DateTime giornoDiPartenza, DateTime oraDa, DateTime oraA,
            bool calcolapausapranzo, int bufferNumeroOre)
        {
            TimeSpan OreDifferenza = (oraA.TimeOfDay - oraDa.TimeOfDay);
            durataStandardMinuti = OreDifferenza.TotalMinutes;
            int oreGiorno = OreDifferenza.Hours;
            while (bufferNumeroOre > 0)
            {
                DateTime oraATemp = oraA;

                if (bufferNumeroOre >= oreGiorno)
                {
                    bufferNumeroOre -= oreGiorno;
                }
                else
                {
                    oraATemp = oraDa.AddHours(bufferNumeroOre);
                    bufferNumeroOre = 0;
                }
                if (calcolapausapranzo)
                {
                    if (oraATemp.TimeOfDay > Properties.Settings.Default.OrarioPausaPranzo)
                        oraATemp = oraATemp.AddMinutes(Properties.Settings.Default.durataPausaPranzo);
                }
                listaDettagli.Add(new DettaglioAttivita()
                {
                    Giorno = giornoDiPartenza.Date,
                    OraInizio = oraDa.Hour,
                    MinutiInizio = oraDa.Minute,
                    OraFine = oraATemp.Hour,
                    MinutiFine = oraATemp.Minute
                });
                giornoDiPartenza = getGiornoDopoValido(giornoDiPartenza);
            }

            return listaDettagli;
        }

        public void RibilanciaDettagli(bool pausaPranzo)
        {
            int overflowOre = 0;
            DateTime dataMax = DateTime.MinValue;
            Dictionary<TimeSpan, int> listaOrariInizio = new Dictionary<TimeSpan, int>();
            Dictionary<TimeSpan, int> listaOrariFine = new Dictionary<TimeSpan, int>();
            foreach (DettaglioAttivita dtt in DettagliAttivita)
            {
                TimeSpan timeInizio = new TimeSpan(dtt.OraInizio, dtt.MinutiInizio, 0);
                if (listaOrariInizio.ContainsKey(timeInizio))
                    listaOrariInizio[timeInizio]++;
                else
                    listaOrariInizio.Add(timeInizio, 1);

                TimeSpan timeFine = new TimeSpan(dtt.OraFine, dtt.MinutiFine, 0);
                if (listaOrariFine.ContainsKey(timeFine))
                    listaOrariFine[timeFine]++;
                else
                    listaOrariFine.Add(timeFine, 1);

                if (dtt.Giorno > dataMax)
                    dataMax = dtt.Giorno;
                overflowOre += (dtt.OraFine - dtt.OraInizio);
            }
            overflowOre = attivita.Corso.NumeroOre - overflowOre;
            TimeSpan asdmax = listaOrariFine.Aggregate((l, r) => l.Value > r.Value ? l : r).Key;
            TimeSpan asdmin = listaOrariInizio.Aggregate((l, r) => l.Value > r.Value ? l : r).Key;
            InserisciOreRimanenti(getGiornoDopoValido(dataMax), dataMax + asdmin, dataMax + asdmax, pausaPranzo, overflowOre);
        }

        public void EliminaGiornoDettaglio(Guid id, bool pausaPranzo)
        {
            double minutiLibere;
            DettaglioAttivita dettDaCancellare =
                listaDettagli.Find(delegate(DettaglioAttivita d) { return d.Id == id; });
            TimeSpan tmFine = new TimeSpan(dettDaCancellare.OraFine, dettDaCancellare.MinutiFine, 0);
            TimeSpan tmInizio = new TimeSpan(dettDaCancellare.OraInizio, dettDaCancellare.MinutiInizio, 0);
            minutiLibere = (tmFine - tmInizio).TotalMinutes;
            if (tmFine > Properties.Settings.Default.OrarioPausaPranzo)
                minutiLibere -= Properties.Settings.Default.durataPausaPranzo;
            listaDettagli.Remove(dettDaCancellare);

            //InserisciOreRimanenti(orada, oraA, pausaPranzo,(int) (tmFine - tmInizio).TotalHours);

            durataStandardMinuti = Properties.Settings.Default.DurataGiornataStandard;
            DettaglioAttivita dettDaAggiungere = new DettaglioAttivita();
            int _ultimoelemento = listaDettagli.Count - 1;
            if (minutiLibere % durataStandardMinuti == 0)
            {
                //aggiungi solo un gg
                dettDaAggiungere.Giorno = getGiornoDopoValido(listaDettagli[_ultimoelemento].Giorno);
                dettDaAggiungere.Id = listaDettagli[_ultimoelemento].Id;
                dettDaAggiungere.OraInizio = listaDettagli[_ultimoelemento].OraInizio;
                dettDaAggiungere.OraFine = listaDettagli[_ultimoelemento].OraFine;
                dettDaAggiungere.MinutiInizio = listaDettagli[_ultimoelemento].MinutiInizio;
                dettDaAggiungere.MinutiFine = listaDettagli[_ultimoelemento].MinutiFine;
            }
            else
            {
                //DA RIVEDERE!
                double calcolo = durataStandardMinuti - minutiLibere;

                dettDaAggiungere.Giorno = getGiornoDopoValido(listaDettagli[_ultimoelemento].Giorno);
                dettDaAggiungere.Id = listaDettagli[_ultimoelemento].Id;
                dettDaAggiungere.OraInizio = listaDettagli[_ultimoelemento].OraInizio;
                dettDaAggiungere.OraFine = Convert.ToInt16(calcolo);
                dettDaAggiungere.MinutiInizio = listaDettagli[_ultimoelemento].MinutiInizio;
                dettDaAggiungere.MinutiFine = listaDettagli[_ultimoelemento].MinutiFine;

                //data = getGiornoDopoValido(data);
                //dataGridViewAttivita.Rows.Add(data, dtOraDa.Value.TimeOfDay, dtOraDa.Value.AddHours(t).TimeOfDay);
            }
            listaDettagli.Add(dettDaAggiungere);
        }

        public void ModificaOrarioGiorno(Guid id,
            DateTime oraDa, DateTime oraA, bool PausaPranzo)
        {
            //if (!ControllaConformitaOrari(oraDa, oraA))
            //    return;

            DettaglioAttivita dettDaModificare
                = listaDettagli.Find(delegate(DettaglioAttivita d) { return d.Id == id; });

            dettDaModificare.OraInizio = oraDa.Hour;
            dettDaModificare.OraFine = oraA.Hour;
            dettDaModificare.MinutiInizio = oraDa.Minute;
            dettDaModificare.MinutiFine = oraA.Minute;
            RibilanciaDettagli(PausaPranzo);
        }

        //private List<int> GetOrarioPiuUsato()
        //{
        //    Dictionary<TimeSpan, int> listaOrari = new Dictionary<TimeSpan, int>();

        //    for (int i = 0; i < listaDettagli.Count; i++)
        //    {
        //        listaOrari.Add(new TimeSpan(listaDettagli[i].OraInizio, listaDettagli[i].MinutiInizio, 0), 1);
        //        if (listaDettagli[i].OraInizio == listaOrari[i])
        //        {
        //            listaOrari.Add(listaDettagli[i].OraInizio);
        //        }
        //    }
        //    return listaOrari;
        //}

        public int ModificaDettagli()
        {
            EliminaTuttiDettagli();
            return Inserisci();
        }

        public void EliminaTuttiDettagli()
        {
            string sql = "delete from DettaglioAttivita "
                + " where idattivita='" + attivita.Id + "'";
            SqlCommand cmd = new SqlCommand(sql, gazelConnector.Connessione);
            cmd.ExecuteNonQuery();
        }

        public bool ControllaConformitaOrari(DateTime oraDa, DateTime oraA)
        {
            try
            {
                TimeSpan OreDifferenza = (new TimeSpan(oraA.Hour, oraA.Minute, 0)
                    - new TimeSpan(oraDa.Hour, oraDa.Minute, 0));
                int.Parse(OreDifferenza.TotalHours.ToString());
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public DateTime getGiornoDopoValido(DateTime data)
        {
            data = data.AddDays(1);
            if (data.DayOfWeek == DayOfWeek.Saturday)
            {
                //se è sabato aggiunge 2 giorni
                return data.AddDays(2);
            }
            else if (data.DayOfWeek == DayOfWeek.Sunday)
            {
                return data.AddDays(1);
            }
            else
            {
                return data;
            }
        }

        public DataTable Ricerca(string condizione = "1=1")
        {
            string sql;
            sql = @"SELECT  DettaglioAttivita.idattivita AS IdAttivita,
                    DettaglioAttivita.id AS Id, Corsi.nome AS Corso, DettaglioAttivita.giorno AS Giorno,
                    DettaglioAttivita.orainizio AS OraInizio, DettaglioAttivita.orafine AS OraFine, DettaglioAttivita.minutiinizio AS MinutiInizio,
                    DettaglioAttivita.minutifine AS MinutiFine
                    FROM Corsi RIGHT OUTER JOIN
                    Attivita ON Corsi.id = Attivita.idcorso RIGHT OUTER JOIN
                    DettaglioAttivita ON Attivita.id = DettaglioAttivita.idattivita";

            sql += " WHERE " + condizione;

            SqlDataAdapter com = new SqlDataAdapter(sql, gazelConnector.Connessione);
            DataTable dt = new DataTable();
            com.Fill(dt);
            return dt;
        }
    }
}